package cn.com.dhcc.turbo.service.transport;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.sql.DataSource;

import org.apache.ftpserver.ConnectionConfig;
import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.filesystem.nativefs.NativeFileSystemFactory;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.ftplet.Ftplet;
import org.apache.ftpserver.impl.DefaultConnectionConfig;
import org.apache.ftpserver.impl.DefaultDataConnectionConfiguration;
import org.apache.ftpserver.impl.PassivePorts;
import org.apache.ftpserver.listener.Listener;
import org.apache.ftpserver.ssl.SslConfiguration;
import org.apache.ftpserver.ssl.SslConfigurationFactory;
import org.apache.ftpserver.usermanager.SaltedPasswordEncryptor;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cn.com.dhcc.app.core.CM;
import cn.com.dhcc.app.core.exception.NiceException;
import cn.com.dhcc.app.core.exception.ServiceException;
import cn.com.dhcc.app.core.handler.modulehandler.WhereCondition;
import cn.com.dhcc.app.core.service.Log;
import cn.com.dhcc.app.core.service.Log.LOGTYPE;
import cn.com.dhcc.app.pub.core.consts.AppConst;
import cn.com.dhcc.app.pub.core.consts.AppConst.EMBFTP;
import cn.com.dhcc.app.pub.core.consts.AppIocBean;
import cn.com.dhcc.app.pub.core.consts.KernelParam;
import cn.com.dhcc.app.pub.core.consts.NodeInfoParam;
import cn.com.dhcc.app.pub.core.listener.FtpletListener;
import cn.com.dhcc.app.pub.core.service.TurboDbUserManagerFactory;
import cn.com.dhcc.app.pub.core.service.TurboFtpListenerFactory;
import cn.com.dhcc.turbo.entity.registry.FtpUser;
import cn.com.dhcc.turbo.entity.registry.NodePipeline.PIPE_STATUS;
import cn.com.dhcc.turbo.service.exch.ApiUserAuthService;
import cn.com.dhcc.turbo.service.exch.exhmgr.FtpUserService;
import cn.com.dhcc.turbo.service.registry.NodeInfoService;
import cn.com.dhcc.turbo.service.registry.NodePipelineService;
import cn.com.dhcc.turbo.service.registry.sync.SynchronizeHandler;
import cn.com.dhcc.turbo.service.registry.vo.PipeLineFtp;

/**
 * 内置FTP监听器
 */
@Component
public class FtpService {
	@Autowired
	NodePipelineService nodePipelineService;
	@Autowired
	NodeInfoService nodeInfoService;
	@Autowired
	SynchronizeHandler synchronizeHandler;
	public static final String FTPSERVER_CONTEXT_NAME = "org.apache.ftpserver";
	
	public static final String KEYSTOREFILE = "ftpkeystore.jks";
	
	public static FtpServer ftpServer;
	@Autowired
	FtpUserService ftpUserService;
	static Object ftpLock = new Object();
	@SuppressWarnings("deprecation")
	Logger ftplogger = Log.getDetachLogger(LOGTYPE.FTP);

	/**
	 * 初始化管理员账号
	 * @throws NiceException
	 */
	public void initFtpAdminUser() throws NiceException {
		FtpUser ftpUserAdmin;
		try {
			ftpUserAdmin = ftpUserService.getFtpadmin();
			if (ftpUserAdmin == null) {
				ftplogger.info("开始创建FTP管理员账号...");
				ftpUserService.createFtpAdmin();
				ftplogger.info("创建FTP管理员账号成功...");
			}else{
				String path = AppConst.EMBFTP.EMBFTP_ROOTDIR + File.separator + AppConst.EMBFTP.EMBFTP_ADMIN_USERID;
				if (!ftpUserAdmin.getHomedirectory().startsWith(path)) {//如果有admin用户目录变化
					
					List<FtpUser> users=ftpUserService.list(new WhereCondition());
					if (users!=null && !users.isEmpty()) {//更新所有的ftp用户
						for (FtpUser ftpUser : users) {
							String newPath=AppConst.EMBFTP.EMBFTP_ROOTDIR + File.separator + ftpUser.getUserid();
							ftpUser.setHomedirectory(newPath);
							ftpUserService.update(ftpUser);;
						}
					}
				}
				
			}
		} catch (ServiceException e) {
			throw new NiceException(e);
		}

	}

	/**
	 * //容器关闭后，关闭ftp
	 * @param servletContext
	 */
	public void stopFtpServer(ServletContext servletContext) {

		try {
			stop();
			ftpServer = null;
			servletContext.log("关闭ftp成功...");
		} catch (NiceException e) {
			servletContext.log(e.getMessage());
		}
	}

	/**
	 * 容器开启时，打开ftp
	 * @param servletContext
	 * @throws NiceException 
	 */
	public void startFtpServer() throws NiceException {
		try {
			start();
			ftplogger.info("ftp启动成功，端口：" + AppConst.EMBFTP.EMBFTP_PORT);
		} catch (NiceException e) {
			throw e;
		}
	}

	int startTimes = 0;

	private void start() throws NiceException {
		if (ftpServer != null) {
			try {
				synchronized (ftpServer) {
					if (ftpServer.isSuspended()) {
						ftpServer.resume();//恢复
					}
					if (ftpServer.isStopped()) {
						ftpServer.start();
					}
				}
				updateLocalFtpStatus(PIPE_STATUS.STARTED);
			} catch (FtpException e) {
				updateLocalFtpStatus(PIPE_STATUS.STOPED);
				throw new NiceException("启动ftp失败", e);
			}
		} else {
			if (startTimes < 2) {//2次还没有初始化成功，就不在尝试初始化了。
				//初始化
				initFtpServer();
				//将参数入库，并同步
				insertLocalFtpPipeLineConfig();
				start();
				startTimes++;
			}
		}
	}

	private void stop() throws NiceException {
		if (ftpServer == null)
		try {
			synchronized (ftpServer) {
				//由于apache FTPserver不提供重启功能如果需要手动关闭serve可以将其进行挂起，以方便恢复
				if (!ftpServer.isStopped() || !ftpServer.isSuspended()) {
					ftpServer.suspend();
				}
			}
		} catch (Exception e) {
			throw new NiceException("关闭ftp失败", e);
		} finally {
			updateLocalFtpStatus(PIPE_STATUS.STOPED);
		}
	}

	public void insertLocalFtpPipeLineConfig() throws NiceException {
		//插入或修改ftp的配置信息到数据库用于同步
		try {
			PipeLineFtp pipeLineFtpInDb = nodePipelineService.getLocalFtpConf();
			PipeLineFtp pipeLineFtp = new PipeLineFtp();
			pipeLineFtp.setRootDir(AppConst.EMBFTP.EMBFTP_ROOTDIR);
			pipeLineFtp.setIp(NodeInfoParam.LOCAL_IP);
			pipeLineFtp.setPort(AppConst.EMBFTP.EMBFTP_PORT);
			pipeLineFtp.setMaxLogins(AppConst.EMBFTP.EMBFTP_MAX_LOGINS);
			if (pipeLineFtpInDb == null || !pipeLineFtpInDb.equals(pipeLineFtp)) {
				nodePipelineService.saveOrUpdateLocalEmbedFtpConf(pipeLineFtp, PIPE_STATUS.STARTED);
			}
		} catch (ServiceException e) {
			throw new NiceException("启动ftp失败：将配置信息入库失败", e);
		}
	}

	public void updateFtpStatus(String nodeId, PIPE_STATUS status) throws NiceException {
		try {
			nodePipelineService.updateFtpStatus(nodeId, status);
		} catch (ServiceException e) {
			throw new NiceException("启动ftp失败：修改ftp状态失败", e);
		}
	}
	public void updateLocalFtpStatus(PIPE_STATUS status) throws NiceException {
		try {
			nodePipelineService.updateLocalFtpStatus(status);
		} catch (ServiceException e) {
			throw new NiceException("启动ftp失败：修改ftp状态失败", e);
		}
	}

	//--------初始化部分
	private static final String INSERT_USER = "INSERT INTO TURBO_FTP_USER (userid, userpassword,"
			+ "homedirectory, enableflag, writepermission, idletime, uploadrate,"
			+ "downloadrate) VALUES ('{userid}', '{userpassword}', '{homedirectory}',"
			+ "'{enableflag}', '{writepermission}', {idletime}, {uploadrate}," + "{downloadrate})";
	private static final String UPDATE_USER = "UPDATE TURBO_FTP_USER SET userpassword='{userpassword}',"
			+ " homedirectory='{homedirectory}',enableflag={enableflag},writepermission={writepermission},"
			+ " idletime={idletime}, uploadrate={uploadrate},downloadrate={downloadrate}" + "  WHERE userid='{userid}'";
	private static final String DELETE_USER = "DELETE FROM TURBO_FTP_USER WHERE userid = '{userid}'";
	private static final String SELECT_USER = "SELECT userid,userpassword,homedirectory,enableflag,writepermission,"
			+ "idletime,uploadrate,downloadrate,maxloginnumber,maxloginperip	"
			+ "FROM TURBO_FTP_USER WHERE userid = '{userid}'";
	private static final String SELECT_ALL_USERS = "SELECT userid FROM TURBO_FTP_USER ORDER BY userid";
	private static final String IS_ADMIN = "SELECT userid FROM TURBO_FTP_USER  WHERE userid='{userid}' AND userid='"
			+ EMBFTP.EMBFTP_ADMIN_USERID + "'";
	private static final String AUTHENTICATE = "SELECT userpassword from TURBO_FTP_USER WHERE userid='{userid}'";

	/**
	 * 初始化ftp
	 * @throws NiceException 
	 */
	private synchronized void initFtpServer() throws NiceException {
		try {
			ftplogger.info("开始初始化内置ftp服务...");
			
			//用户获取方式
			TurboDbUserManagerFactory dbUserManagerFactory = new TurboDbUserManagerFactory();
			dbUserManagerFactory.setDataSource((DataSource) CM.getBeanByName("appDataSource"));
			dbUserManagerFactory.setApiUserAuthService((ApiUserAuthService)CM.getBeanByName(AppIocBean.APIUSER_AUTHSERVICE_IMPL));
			dbUserManagerFactory.setPasswordEncryptor(new SaltedPasswordEncryptor());
			dbUserManagerFactory.setSqlUserAdmin(IS_ADMIN);
			dbUserManagerFactory.setSqlUserAuthenticate(AUTHENTICATE);
			dbUserManagerFactory.setSqlUserDelete(DELETE_USER);
			dbUserManagerFactory.setSqlUserInsert(INSERT_USER);
			dbUserManagerFactory.setSqlUserSelect(SELECT_USER);
			dbUserManagerFactory.setSqlUserSelectAll(SELECT_ALL_USERS);
			dbUserManagerFactory.setSqlUserUpdate(UPDATE_USER);
			
			FtpServerFactory serverFactory = new FtpServerFactory();
			serverFactory.setUserManager(dbUserManagerFactory.createUserManager());
			//连接参数
			int loginFailureDelay = 30;
			int maxLoginFailures = 20;
			int maxAnonymousLogins = maxLoginFailures;
			ConnectionConfig connectionConfig = new DefaultConnectionConfig(false, loginFailureDelay,
					AppConst.EMBFTP.EMBFTP_MAX_LOGINS, maxAnonymousLogins, maxLoginFailures, AppConst.EMBFTP.EMBFTP_MAX_THREADS);
			serverFactory.setConnectionConfig(connectionConfig);
			//文件系统
			NativeFileSystemFactory fileSystemFactory = new NativeFileSystemFactory();
			fileSystemFactory.setCreateHome(true);//自动创建用户根目录(注：是在用户第一次登录的时候创建)
			serverFactory.setFileSystem(fileSystemFactory);
			
		
			
			//监听
			TurboFtpListenerFactory factory = new TurboFtpListenerFactory();
			factory.setPort(AppConst.EMBFTP.EMBFTP_PORT);
			factory.setIdleTimeout(300);
			if (AppConst.installIp.equals(AppConst.mappingIp)) {
				factory.setServerAddress(AppConst.installIp);
			}
			//ssl
			SslConfigurationFactory ssl = null;
			SslConfiguration sslConfiguration = null;
			if(KernelParam.encryptFtpUsessl){
				ssl = new SslConfigurationFactory(); 
				//keytool生成的 证书文件
		        File keystoreFile=new File(getClass().getClassLoader().getResource(KEYSTOREFILE).getFile());  
		        ssl.setKeystoreFile(keystoreFile);  
		        //证书生成时的密码 setKeystorePassword 要注意
		        ssl.setKeyPassword(KernelParam.encryptFtpSslKeypass);   
		        ssl.setKeystorePassword(KernelParam.encryptFtpSslStorepass);
		        //证书类型
		        ssl.setKeystoreType("JKS");
		        ssl.setSslProtocol("SSL");
		        sslConfiguration = ssl.createSslConfiguration();
		        factory.setSslConfiguration(sslConfiguration);
		        factory.setImplicitSsl(true);
			}
			
			//主动被动模式设置
			PassivePorts passivePorts = null;//自定义被动端口管理
			boolean activeEnabled = true;//启动主动模式
			int idleTime = 300;
		    int activeLocalPort = 0;//操作系统自己选择主动端口
		    boolean activeIpCheck = false;
			if (AppConst.EMBFTP.EMBFTP_PASS_PORT!=null && !"".equals(AppConst.EMBFTP.EMBFTP_PASS_PORT.trim())) {
				passivePorts = new TurboPassivePorts(AppConst.EMBFTP.EMBFTP_PASS_PORT, true,true);
			}
			DefaultDataConnectionConfiguration dataConnectionConfig = 
					new DefaultDataConnectionConfiguration(idleTime, sslConfiguration, activeEnabled, activeIpCheck, null, 
							activeLocalPort, null, passivePorts, AppConst.installIp.equals(AppConst.mappingIp)?null:AppConst.mappingIp, false);
			factory.setDataConnectionConfiguration(dataConnectionConfig);
			
			//注：必须在ssl和其他listener参数设置完后才能createListener；
			Listener listener = factory.createListener();
			serverFactory.addListener("default", listener);
			//添加回调
			final Map<String, Ftplet> ftplets = new HashMap<String, Ftplet>();
			ftplets.put("default", new FtpletListener());
			serverFactory.setFtplets(ftplets);
			// create server
			ftpServer = serverFactory.createServer();
			ftplogger.info("初始化内置ftp服务 成功...");
			
			Map<String,Listener> listeners=serverFactory.getListeners();
			if (listeners!=null && !listeners.isEmpty()) {
				
				System.out.println("FTP SERVER启动成功，共启动"+listeners.size()+"个监听器");
				Set<String> set=listeners.keySet();
				for (String key : set) {
					System.out.println("监听器["+key+"],启动ip【"+listeners.get(key).getServerAddress()+"】，端口号【"+listeners.get(key).getPort()+"】,数据传输ip【"+listeners.get(key).getDataConnectionConfiguration().getPassiveExernalAddress()+"】,数据传输端口【"+listeners.get(key).getDataConnectionConfiguration().getPassivePorts()+"】");
				}
			}
		} catch (Exception e) {
			throw new NiceException("初始化ftp失败", e);
		}
	}

	public void initEmbFtp() {
		try {
			startFtpServer();
			initFtpAdminUser();
		} catch (NiceException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}
}
